/*
	Copyright (C) 2011 Salil Bhagurkar

	This file is part of illusion

	illusion is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as
	published by the Free Software Foundation, either version 3 of
	the License, or (at your option) any later version.

	illusion is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with illusion.
	If not, see <http://www.gnu.org/licenses/>.
*/

#include <arch/asmdecl.h>
#include <klib/lib.h>
#include <klib/string.h>
#include <klib/memory.h>
#include <klib/format.h>
#include <kernel/vfs.h>
#include <kernel/list.h>
#include <kernel/errors.h>
#include <kernel/console.h>
#include <kernel/kmalloc.h>
#include <kernel/glist.h>

struct vfs_node *vfs_create_raw_node(struct vfs_node *parent, char *name)
{
	debug("%s in %s\n", name, parent ? parent->name : "<null>");
	struct vfs_node *node = (struct vfs_node *)kmalloc(sizeof(struct vfs_node), "vfs");
	memset(node, 0, sizeof(struct vfs_node));
	strcpy(node->name, name, VFS_NAME_LEN);
	node->parent = parent;
	if(parent) {
		node->dev = parent->dev;
	}
	return node;
}

struct vfs_device *devs, *devs_tail;

struct vfs_device *vfs_create_device(char *name, uint_t rw_unit)
{
	debug("%s\n", name);
	struct vfs_device *dev = (struct vfs_device *)kmalloc(sizeof(struct vfs_device), "vfsd");
	strcpy(dev->name, name, VFS_DEV_NAME_LEN);
	dev->deleted = dev->deleted_tail = null;
	dev->next = dev->prev = null;
	dev->provider = null;
	dev->root = vfs_create_raw_node(null, dev->name);
	dev->root->dev = dev;
	dev->root->flags = VFS_IS_ROOT; //This node is not to be synced;
	//Note that only the children of the root are to be synced. No information
	//about the root is to be synced by default, unless someone writes to it
	//or changes stuff
	//Set the default unit to one byte
	dev->rw_unit = rw_unit;
	list_attach(devs, devs_tail, dev);
	return dev;
}

struct vfs_device *vfs_get_device(char *name)
{
	struct vfs_device *dev;
	list_for(devs, dev) {
		if(streq(dev->name, name)) {
			return dev;
		}
	}
	return null;
}

int vfs_remove_device(char *name, bool force_dispose)
{
	debug("%s\n", name);
	struct vfs_device *dev = vfs_get_device(name);
	if(!dev)
		return ENOENT;
	//Sync all deletions, and dispose
	int err = vfs_sync_dev_deletes(dev->root);
	if(err) {
		debug("Pending sync on dev deletes\n");
		if(!force_dispose)
			return EPENDSYNC;
	}
	//Sync all to dev first
	err = vfs_sync(dev->root);
	if(err) {
		debug("Pending sync on dev root\n");
		if(!force_dispose)
			return EPENDSYNC;
	}
	//Dispose everything
	err = vfs_dispose_node(dev->root, force_dispose);
	if(err) {
		debug("Sync success, but failed to dispose dev root for %s\n",
				name);
		return err;
	}
	//Remove the sync provider if it has not been removed already
	vfs_remove_sync_provider(dev);
	list_detach(devs, devs_tail, dev);
	debug("Dispose Success! (%s)\n", dev->name);
	kfree(dev, sizeof(struct vfs_device), "vfsd");
	return 0;
}

int vfs_set_sync_provider(struct vfs_device *dev, struct vfs_sync_provider *prov)
{
	debug("%s on %s\n", prov->name, dev->name);
	dev->provider = prov;
	return 0;
}

int vfs_remove_sync_provider(struct vfs_device *dev)
{
	if(!(dev->provider))
		return ENOENT;
	debug("%s on %s\n", dev->provider->name, dev->name);
	dev->provider = null;
	return 0;
}

static void print_list(struct vfs_node *parent)
{
	struct vfs_node *temp;
	list_for(parent->child, temp) {
		console_printf("Child of %s = %s\n", parent->name, temp->name);
	}
}

struct vfs_node *vfs_create(struct vfs_node *parent, char *name)
{
	debug("%s in %s\n", name, parent->name);
	struct vfs_node *node = vfs_create_raw_node(parent, name);
	//Mark as new on memory
	node->flags |= VFS_SYNC_MEM | VFS_SYNC_CREATE | VFS_SYNC_TYPE_NODE;
	list_attach(parent->child, parent->child_tail, node);
	parent->child_count++;
	return node;
}

static int __vfs_dispose_node(struct vfs_node *parent, struct vfs_node *node, bool force);



/*
 * Synchronize all deletions to the device, and dispose any memory used
 * Any node under the device may be passed
 */
int vfs_sync_dev_deletes(struct vfs_node *ref_node)
{
	debug("%s\n", ref_node->name);
	struct vfs_node *node;
	for(node = ref_node->dev->deleted; node; ) {
		debug("Sync delete: %s on dev %s\n", node->name, node->dev->name);
		//Sync deletion with device
		int err = vfs_sync_node(node);
		if(err) {
			debug("-->Failed sync\n");
			return err;
		}
		struct vfs_node *next = node->next;
		//Detach from list
		list_detach(ref_node->dev->deleted, ref_node->dev->deleted_tail, node);
		ref_node->dev->deleted_count--;

		__vfs_dispose_node(null, node, 1);
		node = next;
	}
	return 0;
}

int vfs_delete(struct vfs_node *node)
{
	debug("%s\n", node->name);
	//Mark all children for deletion
	struct vfs_node *child;
	for(child = node->child; child; ) {
		struct vfs_node *next = child->next;
		vfs_delete(child);
		child = next;
	}
	debug("Mark vfs_node for deletion: %s\n", node->name);
	//Clear all sync flags
	node->flags &= ~VFS_SYNC_MASK;
	//Mark for deletion
	node->flags = VFS_SYNC_MEM | VFS_SYNC_DELETE | VFS_SYNC_TYPE_NODE;

	//Add to the device's delete list
	struct vfs_node *parent = node->parent;
	list_detach(parent->child, parent->child_tail, node);
	list_attach(node->dev->deleted, node->dev->deleted_tail, node);
	node->dev->deleted_count++;
	return 0;
}

static void dispose_page(struct vfs_node *node, struct vfs_page *page)
{
	debug("%s [%x, %u]\n", node->name, page->start, page->length);
	//First detach the page
	list_detach(node->pages, node->pages_tail, page);
	kfree(page->page_data, page->length, "vfspd");
	kfree(page, sizeof(struct vfs_page), "vfsp");
}

/*
 * Dispose a single node
 */
static int __vfs_dispose_node(struct vfs_node *parent, struct vfs_node *node, bool force)
{
	debug("%s in %s, force=%u\n", node->name, parent ? parent->name : "<null>", force);
	struct vfs_page *page;
	uint_t pending_pages = 0;
	//Free all pages which are synced
	for(page = node->pages; page; ) {
		struct vfs_page *next = page->next;
		if((page->flags & VFS_SYNC_MASK) == 0 || force) {
			dispose_page(node, page);
		} else {
			debug("Page not disposed: [%u, %u unit(s)]\n",
					page->start, page->length);
			pending_pages++;
		}
		page = next;
	}

	if(((node->flags & VFS_SYNC_MASK) == 0 && pending_pages == 0) || force) {
		debug("Disposing node %s (status: %s)\n", node->name, force ? "forced" : "synced");
		//Unlink the node and free it
		if(parent != null) {
			//Remove from the deleted list if present (in case of force=1)
			if(node->flags & VFS_SYNC_DELETE) {
				assert(force == true);
				list_detach(node->dev->deleted, node->dev->deleted_tail, node);
				node->dev->deleted_count--;
			} else {
				//If it is not in the deleted list, it's in the right place
				list_detach(parent->child, parent->child_tail, node);
				parent->child_count--;
			}
		}
		kfree(node, sizeof(struct vfs_node), "vfs");
		return 0;
	} else {
		debug("Node %s not disposed, pending_pages = %u\n", node->name,
				pending_pages);
		return EPENDSYNC;
	}
}

/*
 * Dispose all unnecessary stuff on the node
 */
int vfs_dispose_node(struct vfs_node *node, bool force)
{
	debug("%s force=%u\n", node->name, force);
	struct vfs_node *child;
	//Dispose all children first
	for(child = node->child; child; ) {
		//The node will be unlinked from the list and freed
		//if it gets successfully disposed.
		//Hence, save the next node before we call dispose
		struct vfs_node *next = child->next;
		int err = vfs_dispose_node(child, force);
		if(err) {
			debug("Error [%u] while disposing child %s\n",
					err, child->name);
			return err;
		}
		child = next;
	}
	//Dispose the parent now
	return __vfs_dispose_node(node->parent, node, force);
}

/*
 * Sync the node and pages with its provider
 */
static int __vfs_sync(struct vfs_node *node, u32 flags,
		u32 type)
{
	debug("%s\n", node->name);
	if((node->flags & flags) && (type & VFS_SYNC_TYPE_NODE)) {
		int err = vfs_sync_node(node);
		if(err)
			return err;
	}
	//Sync each page
	if(type & VFS_SYNC_TYPE_PAGE) {
		struct vfs_page *page;
		list_for(node->pages, page) {
			if(page->flags & flags) {
				int err = vfs_sync_page(node, page);
				if(err)
					return err;
			}
		}
	}
	return 0;
}

/*
 * Sync everything that matches the flags
 */
int vfs_sync(struct vfs_node *node)
{
	debug("%s\n", node->name);
	struct vfs_node *child;
	//Sync each one of the children
	for(child = node->child; child; ) {
		//The node will be unlinked from the list and freed
		//if it gets disposed on a delete sync.
		//Hence, save the next node before we call sync on it.
		struct vfs_node *next = child->next;
		int err = vfs_sync(child);
		if(err) {
			debug("Error [%u] while syncing child %s\n",
					err, child->name);
			return err;
		}
		child = next;
	}
	//Sync the parent now
	return __vfs_sync(node, VFS_SYNC_DEV | VFS_SYNC_MEM,
			VFS_SYNC_TYPE_NODE | VFS_SYNC_TYPE_PAGE);
}


/*
 * Sync only the top level members of the node
 */
int vfs_sync_node(struct vfs_node *node)
{
	debug("%s\n", node->name);
	struct vfs_device *dev = node->dev;
	if(dev->provider != null) {
		debug("Sync on provider: %s\n", dev->provider->name);
		int err = dev->provider->sync_node(node);
		if(err != 0) {
			debug("Error [%u] while syncing node %s\n",
					err, node->name);
			return err;
		}
	} else {
		//No provider, keep the node unsynced, but don't return an error
		return 0;
	}
	//Sync was successful, remove the sync flags
	node->flags &= ~VFS_SYNC_MASK;
	return 0;
}

int vfs_sync_page(struct vfs_node *node, struct vfs_page *page)
{
	debug("%s [%x, %u]\n", node->name, page->start, page->length);
	struct vfs_device *dev = node->dev;
	if(dev->provider != null) {
		debug("Sync on provider: %s\n", dev->provider->name);
		int err = dev->provider->sync_page(node, page);
		if(err != 0) {
			debug("Error [%u] while syncing page %u, %u unit(s)\n",
					err, page->start, page->length);
			return err;
		}
	} else {
		//No provider, keep the node unsynced, but don't return an error
		return 0;
	}
	page->flags &= ~VFS_SYNC_MASK;
	return 0;
}

int vfs_rename(struct vfs_node *node, char *new_name)
{
	//Do not allow rename if the device has a newer copy
	//of this node
	if(node->flags & VFS_SYNC_DEV) {
		return EPENDSYNC;
	}
	strcpy(node->name, new_name, VFS_NAME_LEN);
	node->flags |= VFS_SYNC_MEM;
	return 0;
}


/*
 * This will populate all children under a vfs node
 */
int vfs_get_all_children(struct vfs_node *in)
{
	return 0;
}

struct vfs_node *vfs_get_parent(struct vfs_node *node)
{
	return node->parent;
}

static void __vfs_get_path(char *dst, unsigned dst_len, struct vfs_node *node)
{
	if(node == null) {
		return;
	} else if(node->parent == null) {
		strcat(dst, dst_len, node->dev->name);
		strcat(dst, dst_len, ":");
	} else {
		vfs_get_path(dst, dst_len, node->parent);
		strcat(dst, dst_len, "/");
		strcat(dst, dst_len, node->name);
	}
}

char *vfs_get_path(char *dst, unsigned dst_len, struct vfs_node *node)
{
	dst[0] = '\0';
	__vfs_get_path(dst, dst_len, node);
	return dst;
}

/*
 * Gets the first child
 */
struct vfs_node *vfs_get_child(struct vfs_node *node)
{
	struct vfs_node *child = null;
	if(node->child != null) {
		child = node->child;
		//Check for no node caching
		if(node->dev->provider != null) {
			if(node->dev->provider->flags & VFS_SP_NONODECACHE) {
				child->flags |= VFS_SYNC_DEV;
				int err = vfs_sync_node(child);
				if(err)
					return null;
			}
		}
	} else {
		//See if the provider is able to provide us with a child
		if(node->dev->provider != null) {
			child = node->dev->provider->get_child(node);
			if(child != null) {
				list_attach(node->child, node->child_tail, child);
				node->child_count++;
				child->parent = node;
			}
		}
	}
	return child;
}

struct vfs_node *vfs_next_child(struct vfs_node *node)
{
	if(node->next != null) {
		if(node->dev->provider != null) {
			//Check for no node caching
			if(node->dev->provider->flags & VFS_SP_NONODECACHE) {
				node->next->flags |= VFS_SYNC_DEV;
				int err = vfs_sync_node(node->next);
				if(err)
					return null;
			}
		}
		return node->next;
	} else {
		if(node->dev->provider != null) {
			struct vfs_node *child = node->dev->provider->next_child(node);
			if(child != null) {
				list_attach(node->parent->child, node->parent->child_tail, child);
				node->parent->child_count++;
				child->parent = node->parent;
				return child;
			}
		}
	}
	return null;
}


static struct vfs_node *get_child_by_name(struct vfs_node *in, char *name)
{
	struct vfs_node *child;
	if(streq(name, "."))
		return in;
	else if(streq(name, ".."))
		return in->parent;
	list_for(in->child, child) {
		if(streq(child->name, name)) {
			//Check for node caching and call sync
			if(in->dev->provider != null) {
				if(in->dev->provider->flags & VFS_SP_NONODECACHE) {
					child->flags |= VFS_SYNC_DEV;
					int err = vfs_sync_node(child);
					if(err)
						return null;
				}
			}
			return child;
		}
	}
	if(in->dev->provider != null) {
		//See if the underlying sync provider has the uncached child.
		struct vfs_node *pend = vfs_create_raw_node(in, name);
		//We do not attach it to the list, as we don't know as yet, if it exists
		pend->flags |= VFS_SYNC_DEV | VFS_SYNC_TYPE_NODE;
		//See if it can sync in with the file system
		//and check for error as well as fs-specific control structure
		int err = vfs_sync_node(pend);
		if(err != 0 || pend->class == null) {
			//Node does not exist
			kfree(pend, sizeof(struct vfs_node), "vfs");
			return null;
		}
		list_attach(in->child, in->child_tail, pend);
		in->child_count++;
		return pend;
	}
	return null;
}


int vfs_get(struct vfs_node **result, struct vfs_node *from, char *path)
{
	//Separate the device name first
	char *path_i = path;
	char name[VFS_DEV_NAME_LEN];

	*result = null;

	uint_t name_i = 0;
	name[0] = '\0';
	while(*path_i != ':' && *path_i != '\0') {
		name[name_i++] = *path_i;
		name[name_i] = '\0';
		path_i++;
	}
	struct vfs_node *current;
	//We want the device name to end with a ':'
	//If it does not, take it as a relative path
	if(*path_i == ':') {
		//Find the device
		struct vfs_device *dev = vfs_get_device(name);
		if(!dev)
			return ENODEV;

		//Skip over the stupid colon
		path_i++;
		current = dev->root;
	} else {
		//Make it relative to the passed 'from'
		current = from;
		//Start parsing from the start of the path again
		path_i = path;
	}
	//Reset the temporary name array
	name[0] = '\0';
	name_i = 0;
	while(*path_i != '\0') {
		if(*path_i == '/') {
			if(name_i > 0) {
				current = get_child_by_name(current, name);
				if(!current) {
					return ENOENT;
				}
				name[0] = '\0';
				name_i = 0;
			}
		} else {
			name[name_i++] = *path_i;
			name[name_i] = '\0';
		}
		path_i++;
	}
	if(name_i > 0) {
		current = get_child_by_name(current, name);
		if(!current) {
			return ENOENT;
		}
	}
	*result = current;
	return 0;
}

/*
 * 0-10
 * 4000-4049
 * 4050-9000
 *
 * Requested = 5 - 3000
 *
 */

//Temporary list of vfs_pages for describing how the copying must be done
struct __vfs_page_rq {
	struct vfs_page *page;
	uint_t dest_offset;
	struct vfs_page *insert_after;
	struct __vfs_page_rq *next, *prev;
};


//buf_offset is the destination offset where queued read data must be copied over to
static struct __vfs_page_rq *new_read_queue_page(struct vfs_node *node, char *stream, uint_t start,
		uint_t length, uint_t dest_offset, struct vfs_page *insert_after)
{
	struct vfs_page *new_page = (struct vfs_page *)kmalloc(sizeof(struct vfs_page), "vfsp");
	new_page->flags = VFS_SYNC_DEV; //Mark to be synced from the device
	new_page->length = length;
	new_page->next = new_page->prev = null;
	new_page->page_data = kmalloc(new_page->length * node->dev->rw_unit, "vfspd");
	new_page->start = start;
	strcpy(new_page->stream, stream, VFS_STREAM_NAME_LEN);
	struct __vfs_page_rq *q_page = (struct __vfs_page_rq *)kmalloc(sizeof(struct __vfs_page_rq), "vfsprq");
	q_page->page = new_page;
	q_page->dest_offset = dest_offset;
	q_page->next = q_page->prev = null;
	q_page->insert_after = insert_after;
	return q_page;
}



int vfs_read(struct vfs_node *node, char *stream,
		void *buf, uint_t start, uint_t count)
{
	//Validate the bounds of this read
	if(start + count > node->length)
		return EBOUNDS;
	debug("read: %s [%u, %u unit(s)]\n", node->name, start, count);
	//Check if the sync provider requires no caching
	if(node->dev->provider != null) {
		if(node->dev->provider->flags & VFS_SP_NOPAGECACHE) {
			//Create a page
			struct vfs_page page;
			page.flags = VFS_SYNC_DEV;
			page.length = count;
			page.page_data = buf;
			page.start = start;
			strcpy(page.stream, stream, VFS_STREAM_NAME_LEN);
			return node->dev->provider->sync_page(node, &page);
		}
	}
	struct __vfs_page_rq *q_pages = null, *q_pages_tail = null;
	uint_t end = start + count;
	uint_t dest_offset = 0;
	//First search for a page
	struct vfs_page *page;
	list_for(node->pages, page) {
		//Compare with only the stream that was passed
		if(!streq(page->stream, stream))
			continue;
		uint_t page_start = page->start;
		uint_t page_end = page_start + page->length;
		if(start >= page_start && start < page_end) {
			//If a read is pending from the device, complete it
			if(page->flags & VFS_SYNC_DEV) {
				debug("Force sync %u, %u unit(s) on %s\n",
						page_start, page->length, node->name);
				int err = vfs_sync_page(node, page);
				if(err)
					return err;
			}
			uint_t req_len = min(end, page_end) - start;
			debug("Read cache %u, %u unit(s)\n", start, req_len);
			//Page relative start
			uint_t pr_start = start - page_start;
			memcpy(buf + dest_offset * (node->dev->rw_unit),
					page->page_data + pr_start * (node->dev->rw_unit),
					req_len * (node->dev->rw_unit));
			//Remove the read length from the start and count
			start += req_len;
			count -= req_len;
			dest_offset += req_len;
		} else if(start < page_start) {
			//Queue a read
			uint_t req_len = min(page_start, end) - start;
			debug("Queue read %u, %u unit(s)\n", start, req_len);
			struct __vfs_page_rq *new_q_page = new_read_queue_page(node, stream, start, req_len, dest_offset, page->prev);
			list_attach(q_pages, q_pages_tail, new_q_page);
			start += req_len;
			count -= req_len;
			dest_offset += req_len;
		}
		if(count == 0)
			break;
	}
	//See if there is any pending read to be queued
	if(count > 0) {
		debug("Queue read %u, %u unit(s)\n", start, count);
		//We must first figure out where the page will be inserted later on
		struct vfs_page *insert_after = null;
		list_reverse_for(node->pages_tail, page) {
			//Compare with only the stream that was passed
			if(!streq(page->stream, stream))
				continue;
			if(start > page->start) {
				insert_after = page;
				break;
			}
		}
		struct __vfs_page_rq *new_q_page = new_read_queue_page(node, stream, start, count, dest_offset, insert_after);
		list_attach(q_pages, q_pages_tail, new_q_page);
		start += count;
		count -= count;
		dest_offset += count;
	}
	struct __vfs_page_rq *q_page;
	//Queue all pages queued in the temporary list into the main list
	list_for(q_pages, q_page) {
		if(q_page->insert_after != null) {
			list_insert_after(node->pages, node->pages_tail, q_page->insert_after, q_page->page);
		} else {
			list_attach(node->pages, node->pages_tail, q_page->page);
		}
	}
	//Sync to perform the read on the copies which are new on the device
	int err = __vfs_sync(node, VFS_SYNC_DEV, VFS_SYNC_TYPE_PAGE);
	if(!err) {
		debug("Read sync done\n");
		//Complete reads from all pages
		list_for(q_pages, q_page) {
			memcpy(buf + (q_page->dest_offset) * (node->dev->rw_unit),
					q_page->page->page_data,
					q_page->page->length * (node->dev->rw_unit));
		}
	}
	//Now free the temporary queue_page list
	for(q_page = q_pages; q_page; ) {
		struct __vfs_page_rq *next = q_page->next;
		kfree(q_page, sizeof(struct __vfs_page_rq), "vfsprq");
		q_page = next;
	}
	return err;
}



//Temporary list of vfs_pages for attaching to the main list for later writing
struct __vfs_page_wq {
	struct vfs_page *page;
	struct vfs_page *insert_after;
	struct __vfs_page_wq *next, *prev;
};

static struct __vfs_page_wq *new_write_queue_page(struct vfs_node *node, char *stream, uint_t start,
		uint_t length, struct vfs_page *insert_after)
{
	struct vfs_page *new_page = (struct vfs_page *)kmalloc(sizeof(struct vfs_page), "vfsp");
	new_page->flags = VFS_SYNC_MEM; //Mark to be synced to the device
	new_page->length = length;
	new_page->next = new_page->prev = null;
	new_page->page_data = kmalloc(new_page->length * node->dev->rw_unit, "vfspd");
	new_page->start = start;
	strcpy(new_page->stream, stream, VFS_STREAM_NAME_LEN);
	struct __vfs_page_wq *q_page = (struct __vfs_page_wq *)kmalloc(sizeof(struct __vfs_page_wq), "vfspwq");
	q_page->page = new_page;
	q_page->next = q_page->prev = null;
	q_page->insert_after = insert_after;
	return q_page;

}

int vfs_write(struct vfs_node *node, char *stream,
		void *buf, uint_t start, uint_t count)
{
	debug("vfs_write: %s [%u, %u unit(s)]\n", node->name, start, count);
	//Check if the sync provider requires no caching
	if(node->dev->provider != null) {
		if(node->dev->provider->flags & VFS_SP_NOPAGECACHE) {
			//Create a page
			struct vfs_page page;
			page.flags = VFS_SYNC_MEM;
			page.length = count;
			page.page_data = buf;
			page.start = start;
			strcpy(page.stream, stream, VFS_STREAM_NAME_LEN);
			return node->dev->provider->sync_page(node, &page);
		}
	}
	struct __vfs_page_wq *q_pages = null, *q_pages_tail = null;
	uint_t end = start + count;
	uint_t src_offset = 0;
	//First search for a page
	struct vfs_page *page;
	list_for(node->pages, page) {
		//Compare with only the stream that was passed
		if(!streq(page->stream, stream))
			continue;
		uint_t page_start = page->start;
		uint_t page_end = page_start + page->length;
		if(start >= page_start && start < page_end) {
			//If a read is pending from the device, complete it
			if(page->flags & VFS_SYNC_DEV) {
				debug("Force sync %u, %u unit(s) on %s\n",
						page_start, page->length, node->name);
				int err = vfs_sync_page(node, page);
				if(err)
					return err;
			}
			uint_t req_len = min(end, page_end) - start;
			debug("Write cache %u, %u unit(s)\n", start, req_len);
			//Page relative start
			uint_t pr_start = start - page_start;
			memcpy(page->page_data + pr_start * (node->dev->rw_unit),
					buf + src_offset * (node->dev->rw_unit),
					req_len * (node->dev->rw_unit));
			//Remove the read length from the start and count
			start += req_len;
			count -= req_len;
			src_offset += req_len;
			//Change page flags to reflect the current status
			page->flags &= ~VFS_SYNC_MASK;
			page->flags |= VFS_SYNC_MEM;
		} else if(start < page_start) {
			//Queue a write
			uint_t req_len = min(page_start, end) - start;
			debug("Queue write %u, %u unit(s)\n", start, req_len);
			struct __vfs_page_wq *new_q_page = new_write_queue_page(node, stream, start, req_len, page->prev);
			//Copy over the data to the page
			memcpy(new_q_page->page->page_data, buf + src_offset * (node->dev->rw_unit),
					req_len * (node->dev->rw_unit));
			list_attach(q_pages, q_pages_tail, new_q_page);
			start += req_len;
			count -= req_len;
			src_offset += req_len;
		}
		//Break off if we are done
		if(count == 0)
			break;
	}
	//See if there is any pending write to be queued
	if(count > 0) {
		debug("Queue write %u, %u unit(s)\n", start, count);
		//We must first figure out where the page will be inserted later on
		struct vfs_page *insert_after = null;
		list_reverse_for(node->pages_tail, page) {
			//Compare with only the stream that was passed
			if(!streq(page->stream, stream))
				continue;
			if(start > page->start) {
				insert_after = page;
				break;
			}
		}
		struct __vfs_page_wq *new_q_page = new_write_queue_page(node, stream, start, count, insert_after);
		//Copy over the data to the page
		memcpy(new_q_page->page->page_data,
				buf + src_offset * (node->dev->rw_unit),
				count * (node->dev->rw_unit));
		list_attach(q_pages, q_pages_tail, new_q_page);
		start += count;
		count -= count;
		src_offset += count;
	}
	struct __vfs_page_wq *q_page;
	//Queue all pages queued in the temporary list into the main list
	list_for(q_pages, q_page) {
		if(q_page->insert_after != null) {
			list_insert_after(node->pages, node->pages_tail, q_page->insert_after, q_page->page);
		} else {
			list_attach(node->pages, node->pages_tail, q_page->page);
		}
	}
	//Now free the temporary queue_page list
	for(q_page = q_pages; q_page; ) {
		struct __vfs_page_wq *next = q_page->next;
		kfree(q_page, sizeof(struct __vfs_page_wq), "vfspwq");
		q_page = next;
	}
	//Update the length of the node
	if(node->pages_tail) {
		node->length = max(end, (node->pages_tail->start + node->pages_tail->length));
	} else {
		node->length = end;
	}
	//TODO We do not sync immediately in a write
	return 0;
}

static void __print_sync_flags(u32 flags)
{
	if(flags & VFS_SYNC_CREATE)
		debug("  SYNC: Pending Create\n");
	else if(flags & VFS_SYNC_DELETE)
		debug("  SYNC: Pending Delete\n");
	if(flags & VFS_SYNC_DEV) {
		debug("  SYNC: Newer copy with Device\n");
	} else if(flags & VFS_SYNC_MEM) {
		debug("  SYNC: Newer copy with Memory\n");
	} else {
		debug("  SYNCED\n");
	}
}

void debug_vfs_node(struct vfs_node *node)
{
	char path[256];
	debug("Node name: %s\n", node->name);
	vfs_get_path(path, 256, node);
	debug("Node path: %s\n", path);
	debug("State: %u\n", node->state);
	debug("Reference count: %u\n", node->reference);
	__print_sync_flags(node->flags);
	debug("Node device: %s\n", node->dev->name);
	if(node->dev->provider != null) {
		debug("Node device sync provider: %s\n", node->dev->provider->name);
	} else {
		debug("No sync provider on this device\n");
	}
	debug("Node data length: %u\n", node->length);
	if(node->parent != null) {
		debug("Node parent: %s\n", node->parent->name);
	} else {
		debug("No parent\n");
	}
	debug("Now listing pages\n");
	struct vfs_page *page;
	list_for(node->pages, page) {
		debug("Page[%s]: start = %u, length = %u\n", page->stream,
				page->start, page->length);
		__print_sync_flags(page->flags);
	}
}

static void debug_state(struct vfs_node *this, uint_t state)
{
	debug("Requested state = %u, File state %u\n", state, this->state);
	debug("Reference = %u\n", this->reference);
}

int vfs_open(struct vfs_node *node, uint_t state)
{
	debug("Open %s for %u\n", node->name, state);
	if(state > STATE_MAX || state == STATE_CLOSED) {
		debug("Invalid state requested: %u\n", state);
		return EPARAM;
	}
	//Compare states based on the current state
	if(node->state == STATE_CLOSED) {
		node->reference++;
		node->state = state;
		return 0;
	} else if(node->state == STATE_READ) {
		if(state == STATE_READ) {
			node->reference++;
			return 0;
		} else if(state == STATE_WRITE) {
			return EPERMS;
		}
	} else if(node->state == STATE_WRITE) {
		if(state == STATE_READ) {
			return EPERMS;
		} else if(state == STATE_WRITE) {
			return EPERMS;
		}
	} else {
		debug("Invalid file state\n");
		debug_state(node, state);
		return ESTINV;
	}
	return ERETURN;
}

int vfs_close(struct vfs_node *node, uint_t state)
{
	debug("Close %s from %u\n", node->name, state);
	if(state > STATE_MAX || state == STATE_CLOSED) {
		debug("Invalid state requested: %u\n", state);
		return EPARAM;
	}
	if(node->reference == 0) {
		debug("Invalid reference count\n");
		debug_state(node, state);
		return ESTINV;
	}
	//Compare states based on the current state
	if(node->state == STATE_CLOSED) {
		return ESTINV;
	} else if(node->state == STATE_READ) {
		if(state == STATE_READ) {
			node->reference--;
			if(node->reference == 0)
				node->state = STATE_CLOSED;
			return 0;
		}
		debug("Invalid state\n");
		debug_state(node, state);
		return ESTINV;
	} else if(node->state == STATE_WRITE) {
		if(state == STATE_WRITE) {
			if(node->reference == 1) {
				node->reference = 0;
				node->state = STATE_CLOSED;
				return 0;
			}
		}
		debug("Invalid state or reference count\n");
		debug_state(node, state);
		return ESTINV;
	} else {
		debug("Invalid file state\n");
		debug_state(node, state);
		return ESTINV;
	}
	return ERETURN;
}

